#ifndef GRAPHICSVIEW_H
#define GRAPHICSVIEW_H

#include <QGraphicsView>

#include "LeGraphics.h"

class LeGraphicsScene;
class LeGraphicsRuler;
class LeGraphicsRulerBar;

// cppcheck-suppress noConstructor
class LEGRAPHICSVIEW_EXPORT LeGraphicsView : public QGraphicsView
{
    Q_OBJECT

    Q_PROPERTY(Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged)
    Q_PROPERTY(qreal rotation READ rotation WRITE setRotation NOTIFY rotationChanged)
    Q_PROPERTY(InteractionMode interactionMode READ interactionMode WRITE setInteractionMode)
    Q_PROPERTY(QRectF visibleSceneRect READ visibleSceneRect WRITE setVisibleSceneRect NOTIFY visibleSceneRectChanged)

public:
    enum Orientation // TODO: rename to X{Left|Right}Y{Up|Down}
    {
        XRightYUp = 0,
        XRightYDown,
        XLeftYUp,
        XLeftYDown,
    };
    Q_ENUM(Orientation)

    enum InteractionMode
    {
        ZoomMode = 0,
        SingleSelectionMode,
        MultipleSelectionMode,
        HandScrollMode
    };
    Q_ENUM(InteractionMode)

    explicit LeGraphicsView(QWidget *parent = nullptr);

    Orientation orientation() const;
    InteractionMode interactionMode() const;
    qreal rotation() const;
    qreal pixelsPerSceneUnit() const;
    LeGraphicsScene *graphicsScene() const;
    QRectF visibleSceneRect() const;

    void setLeGraphicsScene(LeGraphicsScene *scene);
    LeGraphicsScene *leGraphicsScene() const;

public slots:
    void setInteractionMode(InteractionMode mode);
    void setOrientation(Orientation orientation);
    void setRotation(qreal angle);
    void enableOpenGL(bool enabled); // TODO: Q_PROPERTY and rename to setXyzEnabled
    void enableAntiAliasing(bool enabled);
    void enableProfiling(bool enabled = true);
    void zoomIn();
    void zoomOut();
    void zoomAll();
    void rotateLeft();
    void rotateRight();    
    void setVisibleSceneRect(QRectF rect);
    void setDrawGridInForeground(bool enabled);

signals:
    void rotationChanged(qreal rotation);
    void orientationChanged(Orientation orientation);    
    void visibleSceneRectChanged(QRectF rect);

private:
    void updateViewportCursor(QWidget *viewport);
    void applyTransform();
    void zoomIn(qreal factor);
    void zoomOut(qreal factor);
    void rotateLeft(qreal delta);
    void rotateRight(qreal delta);
    void updateRulers();
    void setupGrid();
    void drawGrid(QPainter *painter, const QRectF &rect);
    void updateSelection();

private:
    bool m_profilingEnabled = false;
    InteractionMode m_interactionMode = MultipleSelectionMode;

    bool m_dragStarted = false;
    bool m_mousePressed = false;
    QPoint m_mousePressScreenPos;
    QPoint m_mousePressViewPoint;
    QPointF m_mousePressScenePos;
    QPoint m_lastMouseMoveScreenPos;
    QPointF m_lastMouseMoveScenePos;

    Orientation m_orientation = XRightYDown;
    qreal m_rotationAngle = 0.0;
    qreal m_scaleFactor = 0.0;

    LeGraphicsRuler *m_hRuler = nullptr;
    LeGraphicsRuler *m_vRuler = nullptr;
    LeGraphicsRulerBar *m_hRulerBar = nullptr;
    LeGraphicsRulerBar *m_vRulerBar = nullptr;
    bool m_drawGridInForeground = true;

    LeGraphicsScene *m_scene = nullptr;

    // QWidget interface
protected:
    virtual void resizeEvent(QResizeEvent *event) override;
    virtual void wheelEvent(QWheelEvent *event) override;
    virtual void paintEvent(QPaintEvent *event) override;
    virtual void mousePressEvent(QMouseEvent *event) override;
    virtual void mouseReleaseEvent(QMouseEvent *event) override;
    virtual void mouseMoveEvent(QMouseEvent *event) override;
    virtual void mouseDoubleClickEvent(QMouseEvent *event) override;

    // QAbstractScrollArea interface
public:
    virtual void setupViewport(QWidget *viewport) override;

    // QGraphicsView interface
protected:
    virtual void drawBackground(QPainter *painter, const QRectF &rect) override;
    virtual void drawForeground(QPainter *painter, const QRectF &rect) override;

    // QWidget interface
protected:
    virtual void keyPressEvent(QKeyEvent *event) override;
    virtual void keyReleaseEvent(QKeyEvent *event) override;
    virtual void focusInEvent(QFocusEvent *event) override;
    virtual void focusOutEvent(QFocusEvent *event) override;
    virtual void enterEvent(QEvent *event) override;
    virtual void leaveEvent(QEvent *event) override;
};

#endif // GRAPHICSVIEW_H
